﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MC_AI_002
{
    /* TrackGroup objects contain Track objects that are connected to each other in a single unified piece */
    // funtionality to be added in next step: adding neighbor chains, destroying neighbor chains
    // step + 1 functionality: remove tracks, see if it causes a continuity problem, splitting group into multiple groups
    class TrackGroup
    {
        /* Private variable declarations */
        private static int S_ID = 0;
        private int m_ID;

        private List<Track> T_List;

        public TrackGroup()
        {
            m_ID = S_ID++;
            T_List = new List<Track>();

            //Console.Write("\tNew TrackGroup["+m_ID+"] added!\n");
        }
        public TrackGroup(Track firstMember)
        {
            m_ID = S_ID++;
            T_List = new List<Track>();

            //Console.Write("\tNew TrackGroup["+m_ID+"] added!\n");
            this.addTrack(firstMember);
        }
        public TrackGroup(List<Track> allMembers)
        {
            m_ID = S_ID++;
            T_List = allMembers;
        }
        public int getNumMembers()
        {
            try
            {
                return T_List.Count(); // attempt to return the count
            }
            catch (System.ArgumentNullException) // if the count = 0 or T_List == null then return 0
            {
                return 0;
            }
        }
        public void removeTrack(Track t)
        {
            Console.WriteLine("Attempting to remove Track[{0}] from TrackGroup[{1}]", t.getID(), this.getID());
            T_List.Remove(t);

            if (this.contains(t))
            {
                
                    Console.WriteLine("\tRemoval of Track[{0}] from TrackGroup[{1}] failed", t.getID(), this.getID());
                    Console.Write("\tTrying again but by index...");
                    // get index of t
                    int index_t = T_List.IndexOf(t);
                    Console.Write("Track[{0}]...", index_t);
                    if (index_t >= 0 && index_t < T_List.Count())
                    {
                        T_List.RemoveAt(index_t);
                    }

                    if (this.contains(t))
                    {
                        Console.Write("Failed");
                    }
                    else
                    {
                        Console.Write("Success");
                    }
                
                Console.WriteLine();
            }
            else
            {
                Console.WriteLine("\tRemoval of Track[{0}] from TrackGroup[{1}] succeeded", t.getID(), this.getID());
            }
        }
        public void addTrack(Track t)
        {
            // make sure that track t is not null
            if (t != null)
            {
                T_List.Add(new Track(t));
            }
        }
        public Track getClosestMember(Track testTrack, float maxDistance)
        {
            if (getNumMembers() > 0)
            {
                float distance = 0.0f, pDistance = 0.0f;
                int firstID = T_List.First().getID();
                int bestID = firstID;
                Track retTrack = null;

                float[] t_coord = testTrack.getCoords(), m_coord;
                foreach (Track t in T_List)
                {
                    m_coord = t.getCoords();

                    if (t.getID() == firstID)
                    {
                        pDistance = getDistance(t_coord, m_coord);
                        retTrack = t; // here just in case the firstID is also the lastID
                    }
                    else
                    {
                        distance = getDistance(t_coord, m_coord);
                        if (pDistance > distance)
                        {
                            pDistance = distance;
                            bestID = t.getID();
                            retTrack = t;
                        }
                    }
                }
                //Console.WriteLine("Max Distance = {0} ; Best Distance = {1}; Best ID = {2}", maxDistance, pDistance,bestID);
                //Console.WriteLine("Best Distance <= Max Distance = {0}", pDistance <= maxDistance);
                if (pDistance <= maxDistance)
                {
                    //Console.WriteLine("returnTrack.ID = {0}", retTrack.getID());
                    return retTrack;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
        public float getDistance(float[] a, float[] b)
        {
            return (float)Math.Sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]));
        }

        public int getID()
        {
            return m_ID;
        }
        public bool contains(Track track)
        {
            foreach (Track T in T_List)
            {
                if (T.isEqual(track))
                {
                    return true;
                }
            }
            return false;
        }
        public bool contains(int trackID) // looks for trackID amongst its lists
        {
            foreach (Track T in T_List)
            {
                if (T.getID() == trackID)
                {
                    return true;
                }
            }
            return false;
        }

        public Track getTrackByID(int trackID)
        {
            foreach (Track T in T_List){
                if (T.getID() == trackID)
                {
                    return T;
                }
            }
            return null; // should never happen if contains(trackID) is done before this one
        }

        public void printMembers()
        {
            foreach (Track T in T_List)
            {
                Console.Write("\tTrack[{0}] has {1} Neighbors\n",T.getID(),T.getNumNeighbors());
                T.printNeighbors();
            }
        }

        public List<Track> getAllTracks()
        {
            return T_List;
        }

        public void merge(List<Track> newItems)
        {
            foreach (Track T in newItems){
                this.addTrack(T);
            }
        }
        public void clearList()
        {
            T_List.Clear();
        }
    }
}
